home *** CD-ROM | disk | FTP | other *** search
/ APDL Other Worlds / APDL Other Worlds Collection.iso / SF3000 / Extras / !SFtoSpr / c / Scan < prev    next >
Encoding:
Text File  |  2003-11-06  |  34.6 KB  |  999 lines

  1. /*
  2.  *  SFtoSpr - Star Fighter 3000 graphics converter
  3.  *  Directory scan
  4.  *  Copyright (C) 2000  Chris Bazley
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public Licence as published by
  8.  *  the Free Software Foundation; either version 2 of the Licence, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public Licence for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public Licence
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  */
  20.  
  21. /* ANSI library files */
  22. #include <stdlib.h>
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <stdbool.h>
  26. #include <assert.h>
  27.  
  28. /* RISC OS library files */
  29. #include "kernel.h"
  30. #include "wimp.h"
  31. #include "toolbox.h"
  32. #include "event.h"
  33. #include "wimplib.h"
  34. #include "window.h"
  35. #include "gadgets.h"
  36. #include "flex.h"
  37.  
  38. /* My library files */
  39. #include "err.h"
  40. #include "msgtrans.h"
  41. #include "hourglass.h"
  42. #include "SprFormats.h"
  43. #include "SFformats.h"
  44. #include "FedCompMT.h"
  45. #include "ViewsMenu.h"
  46. #include "Loader.h"
  47. #include "Macros.h"
  48. #include "NoBudge.h"
  49. #include "RoundRobin.h"
  50. #include "LoadSaveMT.h"
  51. #include "AbortFop.h"
  52.  
  53. /* Local headers */
  54. #include "SFgfxconv.h"
  55. #include "Utils.h"
  56. #include "Main.h"
  57. #include "Scan.h"
  58.  
  59. /* gadget IDs */
  60. #define SCAN_ACTIVITY     0x0c
  61. #define SCAN_PATH         0x0d
  62. #define SCAN_SCANNED      0x0a
  63. #define SCAN_CONVERTED    0x0b
  64. #define SCAN_ABORT        0x01
  65. #define SCAN_SKIP         0x02
  66. #define SCAN_RESTART      0x03
  67. #define SCAN_FOURTHBUTTON 0x04
  68. #define SCAN_MESSAGE      0x05
  69.  
  70. #define SCAN_PHASE_DUMMY     -3
  71. #define SCAN_PHASE_ERROR     -2
  72. #define SCAN_PHASE_PAUSE     -1
  73. #define SCAN_PHASE_IDLE      0
  74. #define SCAN_PHASE_SCANNING  1
  75. #define SCAN_PHASE_LOAD      2
  76. #define SCAN_PHASE_LOADANIMS 3
  77. #define SCAN_PHASE_CONVERT   4
  78. #define SCAN_PHASE_SAVE      5
  79. #define SCAN_PHASE_SAVEANIMS 6
  80.  
  81. typedef struct
  82. {  int loadaddr;
  83.    int execaddr;
  84.    int length;
  85.    int attributes;
  86.    int objecttype;
  87.    int filetype;
  88.    char filename[256];
  89. } OSGBPBblock;
  90.  
  91. typedef struct _ScanData
  92. {
  93.   ObjectId window_id; /* dialogue window */
  94.   char *loadroot;
  95.   char *saveroot;
  96.   int phase; /* what is going on */
  97.   int level;
  98.   int numchecked;
  99.   int numoutput;
  100.  
  101.   char *loadpath;
  102.  
  103.   void *input_buffer; /* flex block */
  104.   int input_type;
  105.   SF_MapTilesSetHdr anims;
  106.  
  107.   bool conv_to_sf3000;
  108.   bool conv_to_tile;
  109.   void *output_buffer; /* flex block */
  110.   int output_type;
  111.  
  112.   char *savepath; /* "root"+"relative_dir"+"leafname" */
  113.  
  114.   char *relativedir;
  115.  
  116.   int *position; /* position on each level of tree */
  117.  
  118.   int return_phase; /* for pause, error */
  119.   /* preserved data for retry */
  120.   int retry_numchecked;
  121.   int retry_numoutput;
  122.   int retry_position;
  123.   FILE **thread_state;
  124.   char return_action[16];
  125. } ScanData;
  126.  
  127. /* ----------------------------------------------------------------------- */
  128. /*                       Function prototypes                               */
  129.  
  130. static void _Scan_displayerror(ScanData *scan_data, char *errormessage);
  131. static void _Scan_displayprogress(ScanData *scan_data);
  132. static void _Scan_updatewindow(ScanData *scan_data, const char *action, const char *filepath);
  133. static int _Scan_scanforfile(ScanData *scan_data);
  134. static int _Scan_convertdata(ScanData *scan_data);
  135. static int _Scan_loadfile(ScanData *scan_data, const volatile bool *time_up);
  136. static int _Scan_loadanimsfile(ScanData *scan_data);
  137. static int _Scan_savefile(ScanData *scan_data, const volatile bool *time_up);
  138. static int _Scan_saveanimsfile(ScanData *scan_data);
  139. static RoundRobinHandler _Scan_pollhandler;
  140. static ToolboxEventHandler _Scan_buttonhandler, _Scan_deletedhandler;
  141.  
  142. /* ----------------------------------------------------------------------- */
  143. /*                         Public functions                                */
  144.  
  145. ObjectId Scan_create(char *newloadroot, char *newsaveroot, bool tosf3000)
  146. {
  147.   char *titletok, *convnametok;
  148.   ScanData *newscan_data;
  149.  
  150.   /* Allocate space for thread data */
  151.   newscan_data = malloc(sizeof(ScanData));
  152.   if(newscan_data == NULL)
  153.     MG_RETV("NoMem", NULL_ObjectId) /* failure */
  154.  
  155.   /* Create scan progress window */
  156.   if(E(toolbox_create_object(0, "Scan", &newscan_data->window_id)))
  157.     goto errexit1;
  158.  
  159.   /* Add to window list */
  160.   if(tosf3000) {
  161.     convnametok = "ScanSprSFList";
  162.     titletok = "ScanSprSFTitle";
  163.   }
  164.   else {
  165.     convnametok = "ScanSFSprList";
  166.     titletok = "ScanSFSprTitle";
  167.   }
  168.   if(E(window_set_title(0, newscan_data->window_id, msgs_lookup(titletok))))
  169.     goto errexit2;
  170.   if(E(ViewsMenu_add(newscan_data->window_id, msgs_lookup_sub1(convnametok, tail(newloadroot, 3)), "")))
  171.     goto errexit2;
  172.  
  173.   /* register to receive null polls */
  174.   if(E(RoundRobin_register(_Scan_pollhandler, newscan_data)))
  175.     goto errexit3;
  176.  
  177.   /* Allocate memory */
  178.   newscan_data->loadpath = NULL;
  179.   newscan_data->savepath = NULL;
  180.   newscan_data->loadroot = copystring(newloadroot);
  181.   if(newscan_data->loadroot == NULL)
  182.     goto errexit4;
  183.   newscan_data->saveroot = copystring(newsaveroot);
  184.   if(newscan_data->saveroot == NULL)
  185.     goto errexit5;
  186.   newscan_data->relativedir = copystring("");
  187.   if(newscan_data->relativedir == NULL)
  188.     goto errexit6;
  189.   newscan_data->position = malloc(sizeof(int));
  190.   if(newscan_data->position == NULL)
  191.     goto errexit7;
  192.  
  193.   /* Unallocated flex anchors */
  194.   newscan_data->input_buffer = NULL;
  195.   newscan_data->output_buffer = NULL;
  196.  
  197.   /* Initialise thread variables */
  198.   newscan_data->level = 0;
  199.   newscan_data->position[newscan_data->level] = 0;
  200.   newscan_data->numchecked = 0;
  201.   newscan_data->numoutput = 0;
  202.   newscan_data->conv_to_sf3000 = tosf3000; /* conversion mode */
  203.   newscan_data->phase = SCAN_PHASE_SCANNING;
  204.  
  205.   /* Register event handlers
  206.      Note that ObjectDeleted handler is registered AFTER anything that could cause an error and therefore premature deletion!
  207.   */
  208.   if(!E(event_register_toolbox_handler(newscan_data->window_id, ActionButton_Selected, _Scan_buttonhandler, newscan_data))
  209.   && !E(event_register_toolbox_handler(newscan_data->window_id, Toolbox_ObjectDeleted,  _Scan_deletedhandler, newscan_data))) {
  210.  
  211.     /* Set up window */
  212.     _Scan_displayprogress(newscan_data);
  213.     _Scan_updatewindow(newscan_data, msgs_lookup("ScanTOpen"), newscan_data->loadroot);
  214.     RE(button_set_value(0, newscan_data->window_id, SCAN_CONVERTED, "0"))
  215.     RE(button_set_value(0, newscan_data->window_id, SCAN_SCANNED, "0"))
  216.  
  217.     return newscan_data->window_id; /* initialisation successful */
  218.   }
  219.  
  220.   errexit7:
  221.     free(newscan_data->relativedir);
  222.   errexit6:
  223.     free(newscan_data->saveroot);
  224.   errexit5:
  225.     free(newscan_data->loadroot);
  226.   errexit4:
  227.     RoundRobin_deregister(_Scan_pollhandler, newscan_data);
  228.   errexit3:
  229.     RE(ViewsMenu_remove(newscan_data->window_id))
  230.   errexit2:
  231.     RE(toolbox_delete_object(0, newscan_data->window_id))
  232.   errexit1:
  233.     free(newscan_data);
  234.     return NULL_ObjectId; /* failure */
  235. }
  236.  
  237. /* ----------------------------------------------------------------------- */
  238. /*                         Private functions                               */
  239.  
  240. static void _Scan_pollhandler(void *handle, const volatile bool *time_up)
  241. {
  242.   ScanData *scan_data = (ScanData *)handle;
  243.   int new_phase = SCAN_PHASE_DUMMY;
  244.  
  245.   err_suppress_errors(); /* suppress and record errors */
  246.  
  247.   switch(scan_data->phase) {
  248.     case SCAN_PHASE_SCANNING:
  249.       new_phase = _Scan_scanforfile(scan_data);
  250.       break;
  251.  
  252.     case SCAN_PHASE_LOAD:
  253.       new_phase = _Scan_loadfile(scan_data, time_up);
  254.       break;
  255.  
  256.     case SCAN_PHASE_LOADANIMS:
  257.       new_phase = _Scan_loadanimsfile(scan_data);
  258.       break;
  259.  
  260.     case SCAN_PHASE_CONVERT:
  261.       new_phase = _Scan_convertdata(scan_data);
  262.       break;
  263.  
  264.     case SCAN_PHASE_SAVE:
  265.       new_phase = _Scan_savefile(scan_data, time_up);
  266.       break;
  267.  
  268.     case SCAN_PHASE_SAVEANIMS:
  269.       new_phase = _Scan_saveanimsfile(scan_data);
  270.       break;
  271.   }
  272.  
  273.   if(new_phase != SCAN_PHASE_DUMMY)
  274.     scan_data->phase = new_phase;
  275.  
  276.   if(new_phase == SCAN_PHASE_ERROR) {
  277.     /* free any allocated buffers */
  278.     if(scan_data->input_buffer != NULL)
  279.       flex_free((flex_ptr)&scan_data->input_buffer);
  280.     if(scan_data->output_buffer != NULL)
  281.       flex_free((flex_ptr)&scan_data->output_buffer);
  282.  
  283.     /* turn progress window into error box */
  284.     _Scan_displayerror(scan_data, err_dump_suppressed()->errmess);
  285.     RoundRobin_deregister(_Scan_pollhandler, handle); /* cease null-polling */
  286.   }
  287.   else
  288.     err_dump_suppressed(); /* Allow up-front errors again */
  289. }
  290.  
  291. /* ----------------------------------------------------------------------- */
  292.  
  293. static int _Scan_buttonhandler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
  294. {
  295.   ScanData *scan_data = (ScanData *)handle;
  296.   char *new_ptr;
  297.   if(scan_data->phase != SCAN_PHASE_ERROR) {
  298.  
  299.     switch(id_block->self_component) {
  300.       case SCAN_ABORT: /* Abort */
  301.         RE(toolbox_delete_object(0,scan_data->window_id))
  302.         return 1; /* claim event */
  303.  
  304.       case SCAN_FOURTHBUTTON: /* Pause/Continue */
  305.         if(scan_data->phase == SCAN_PHASE_PAUSE) {
  306.           /* unpause it */
  307.           RE(actionbutton_set_text(0, scan_data->window_id, SCAN_FOURTHBUTTON, (char *)msgs_lookup("ScanBPause")))
  308.           RE(gadget_set_help_message(0, scan_data->window_id, SCAN_FOURTHBUTTON, (char *)msgs_lookup("ScanHPause")))
  309.           RE(button_set_value(0, scan_data->window_id, SCAN_ACTIVITY, scan_data->return_action))
  310.           scan_data->phase = scan_data->return_phase;
  311.           RE(RoundRobin_register(_Scan_pollhandler, handle)) /* resume null-polling */
  312.         }
  313.         else {
  314.           /* pause it */
  315.           RE(actionbutton_set_text(0, scan_data->window_id, SCAN_FOURTHBUTTON, (char *)msgs_lookup("ScanBCont")))
  316.           RE(gadget_set_help_message(0, scan_data->window_id, SCAN_FOURTHBUTTON, (char *)msgs_lookup("ScanHCont")))
  317.           RE(button_get_value(0, scan_data->window_id, SCAN_ACTIVITY, scan_data->return_action, sizeof(scan_data->return_action), NULL))
  318.           RE(button_set_value(0, scan_data->window_id, SCAN_ACTIVITY, (char *)msgs_lookup("ScanTPaused")))
  319.           scan_data->return_phase = scan_data->phase;
  320.           scan_data->phase = SCAN_PHASE_PAUSE;
  321.           RoundRobin_deregister(_Scan_pollhandler, handle); /* cease null-polling */
  322.         }
  323.         return 1; /* claim event */
  324.  
  325.       default:
  326.         return 0; /* pass event on */
  327.     }
  328.   }
  329.   else {
  330.     /* Houston, we have a problem */
  331.     switch(id_block->self_component) {
  332.       case SCAN_ABORT:/* Abort */
  333.         RE(toolbox_delete_object(0,scan_data->window_id))
  334.         return 1; /* claim event */
  335.  
  336.       case SCAN_SKIP:/* Skip to next file */
  337.         _Scan_displayprogress(scan_data);
  338.         scan_data->phase = SCAN_PHASE_SCANNING;
  339.         RE(RoundRobin_register(_Scan_pollhandler, handle)) /* resume null-polling */
  340.         return 1; /* claim event */
  341.  
  342.       case SCAN_RESTART:/* Restart */
  343.         scan_data->level = 0;
  344.         scan_data->position[scan_data->level] = 0;
  345.         scan_data->numchecked = 0;
  346.         scan_data->numoutput = 0;
  347.         new_ptr = copystring("");
  348.         if(new_ptr == NULL)
  349.             return 1; /* claim event */
  350.         free(scan_data->relativedir);
  351.         scan_data->relativedir = new_ptr;
  352.         _Scan_displayprogress(scan_data);
  353.         _Scan_updatewindow(scan_data,msgs_lookup("ScanTOpen"),scan_data->loadroot);
  354.         RE(button_set_value(0, scan_data->window_id, SCAN_SCANNED, "0"))
  355.         RE(button_set_value(0, scan_data->window_id, SCAN_CONVERTED, "0"))
  356.  
  357.         scan_data->phase = SCAN_PHASE_SCANNING;
  358.         RE(RoundRobin_register(_Scan_pollhandler, handle)) /* resume null-polling */
  359.         return 1;
  360.  
  361.       case SCAN_FOURTHBUTTON:/* Retry */
  362.         _Scan_displayprogress(scan_data);
  363.         scan_data->numchecked = scan_data->retry_numchecked;
  364.         {
  365.           char num[16];
  366. #ifndef OLD_SCL_STUBS
  367.           snprintf(num, sizeof(num), "%d", scan_data->numchecked);
  368. #else
  369.           sprintf(num, "%d", scan_data->numchecked);
  370. #endif
  371.           RE(button_set_value(0, scan_data->window_id, SCAN_SCANNED, num))
  372.         }
  373.         scan_data->numoutput = scan_data->retry_numoutput;
  374.         {
  375.           char num[16];
  376. #ifndef OLD_SCL_STUBS
  377.           snprintf(num, sizeof(num), "%d", scan_data->numoutput);
  378. #else
  379.           sprintf(num, "%d", scan_data->numoutput);
  380. #endif
  381.           RE(button_set_value(0, scan_data->window_id, SCAN_CONVERTED, num))
  382.         }
  383.         scan_data->position[scan_data->level] = scan_data->retry_position;
  384.         scan_data->phase = SCAN_PHASE_SCANNING;
  385.         RE(RoundRobin_register(_Scan_pollhandler, handle)) /* resume null-polling */
  386.         return 1; /* claim event */
  387.  
  388.       default:
  389.         return 0; /* event not handled */
  390.     }
  391.   }
  392. }
  393.  
  394. /* ----------------------------------------------------------------------- */
  395.  
  396. static int _Scan_deletedhandler(int event_code, ToolboxEvent *event, IdBlock *id_block, void *handle)
  397. {
  398.   ScanData *scan_data = (ScanData *)handle;
  399.  
  400.   if(scan_data->phase != SCAN_PHASE_ERROR
  401.   && scan_data->phase != SCAN_PHASE_PAUSE)
  402.     RoundRobin_deregister(_Scan_pollhandler, handle); /* if we were null polling then stop */
  403.  
  404.   RE(event_deregister_toolbox_handler(id_block->self_id, ActionButton_Selected, _Scan_buttonhandler, handle))
  405.   RE(event_deregister_toolbox_handler(id_block->self_id, Toolbox_ObjectDeleted, _Scan_deletedhandler, handle))
  406.  
  407.   RE(ViewsMenu_remove(id_block->self_id))
  408.  
  409.   /* free all memory for this op */
  410.   if(scan_data->input_buffer != NULL)
  411.     flex_free((flex_ptr)&scan_data->input_buffer);
  412.   if(scan_data->output_buffer != NULL)
  413.     flex_free((flex_ptr)&scan_data->output_buffer);
  414.  
  415.   free(scan_data->position);
  416.   free(scan_data->loadpath);
  417.   free(scan_data->savepath);
  418.   free(scan_data->relativedir);
  419.  
  420.   /* and finally... */
  421.   free(scan_data->loadroot);
  422.   free(scan_data->saveroot);
  423.  
  424.   /* free state and close down any running thread */
  425.   if(scan_data->thread_state != NULL) {
  426.     if(scan_data->phase == SCAN_PHASE_LOAD 
  427.     || (scan_data->phase == SCAN_PHASE_PAUSE && scan_data->return_phase == SCAN_PHASE_LOAD)
  428.     || scan_data->phase == SCAN_PHASE_SAVE
  429.     || (scan_data->phase == SCAN_PHASE_PAUSE && scan_data->return_phase == SCAN_PHASE_SAVE))
  430.       abort_file_op(&scan_data->thread_state);
  431.   }
  432.  
  433.   free(scan_data);
  434.   return 1;
  435. }
  436.  
  437. /* ----------------------------------------------------------------------- */
  438.  
  439. static void _Scan_displayerror(ScanData *scan_data, char *errormessage)
  440. {
  441.   /* opens progress window to centre of screen at expanded size and sets up buttons */
  442.   WindowShowObjectBlock wsob;
  443.   int cernX,cernY;
  444.   RE(showgadget(scan_data->window_id, SCAN_SKIP));
  445.   /* Can't 'Skip' if stuck at end of directory (error leaving it),
  446.   or if scan_data->position wasn't updated (error calling OS_GBPB) */
  447.   RE(set_gadget_faded(
  448.     (scan_data->position[scan_data->level] == -1 || scan_data->position[scan_data->level] == scan_data->retry_position),
  449.     scan_data->window_id,
  450.     SCAN_SKIP
  451.   ));
  452.   RE(showgadget(scan_data->window_id, SCAN_RESTART));
  453.   RE(actionbutton_set_text(0, scan_data->window_id, SCAN_FOURTHBUTTON, (char *)msgs_lookup("ScanBRetry")));
  454.   RE(gadget_set_help_message(0, scan_data->window_id, SCAN_FOURTHBUTTON, (char *)msgs_lookup("ScanHRetry")));
  455.   RE(button_set_value(0, scan_data->window_id, SCAN_MESSAGE, errormessage));
  456.   /* Alter visible area and centre */
  457.   RE(getscreencentre(&cernX, &cernY))
  458.   wsob.visible_area.xmin = cernX - (736/2);
  459.   wsob.visible_area.ymax = cernY + (596/2);
  460.   wsob.visible_area.xmax = cernX + (736/2);
  461.   wsob.visible_area.ymin = cernY - (596/2);
  462.   wsob.xscroll = 0;wsob.yscroll = 0;
  463.   wsob.behind = -1; /* top of stack */
  464.   RE(ViewsMenu_show_object(0, scan_data->window_id, Toolbox_ShowObject_FullSpec, &wsob, 0, 0))
  465.   /* N.B. consider the fact that window may be iconised */
  466. }
  467.  
  468. /* ----------------------------------------------------------------------- */
  469.  
  470. static void _Scan_displayprogress(ScanData *scan_data)
  471. {
  472.   WimpGetWindowInfoBlock windowinfo;
  473.   WindowShowObjectBlock wsob;
  474.   /* reduces progress window to normal size, restores normal buttons */
  475.   RE(hidegadget(scan_data->window_id, SCAN_SKIP))
  476.   RE(hidegadget(scan_data->window_id, SCAN_RESTART))
  477.   if(scan_data->phase == SCAN_PHASE_PAUSE) {
  478.     RE(actionbutton_set_text(0, scan_data->window_id, SCAN_FOURTHBUTTON, (char *)msgs_lookup("ScanBCont")))
  479.     RE(gadget_set_help_message(0, scan_data->window_id, SCAN_FOURTHBUTTON, (char *)msgs_lookup("ScanHCont")))
  480.   }
  481.   else {
  482.     RE(actionbutton_set_text(0, scan_data->window_id, SCAN_FOURTHBUTTON, (char *)msgs_lookup("ScanBPause")))
  483.     RE(gadget_set_help_message(0, scan_data->window_id, SCAN_FOURTHBUTTON, (char *)msgs_lookup("ScanHPause")))
  484.   }
  485.   /* Alter visible area but not position */
  486.   RE(window_get_wimp_handle(0, scan_data->window_id, &windowinfo.window_handle))
  487.   RE(wimp_get_window_info_no_icon_data(&windowinfo))
  488.   wsob.visible_area.xmin = windowinfo.window_data.visible_area.xmin;
  489.   wsob.visible_area.ymax = windowinfo.window_data.visible_area.ymax;
  490.   wsob.visible_area.xmax = windowinfo.window_data.visible_area.xmin + 620;
  491.   wsob.visible_area.ymin = windowinfo.window_data.visible_area.ymax - 252;
  492.   wsob.xscroll = 60;
  493.   wsob.yscroll = 0;
  494.   wsob.behind = windowinfo.window_data.behind;
  495.   RE(toolbox_show_object(0, scan_data->window_id, Toolbox_ShowObject_FullSpec, &wsob, 0, 0))
  496.   /* N.B. window can never be iconised at this point (function called when just created, or as result of button press) */
  497. }
  498.  
  499. /* ----------------------------------------------------------------------- */
  500.  
  501. static void _Scan_updatewindow(ScanData *scan_data, const char *action, const char *filepath)
  502. {
  503.   /* Only update action text if not the same */
  504.   {
  505.     char current_action[16];
  506.     RE(button_get_value(0, scan_data->window_id, SCAN_ACTIVITY, current_action, sizeof(current_action), NULL))
  507.     if(strcmp(current_action, action) != 0)
  508.       RE(button_set_value(0, scan_data->window_id, SCAN_ACTIVITY, (char *)action))
  509.   }
  510.  
  511.   /* Whereas file paths are v. unlikely to be the same (impossible?) */
  512.   RE(button_set_value(0, scan_data->window_id, SCAN_PATH, (char *)filepath))
  513. }
  514.  
  515. /* ----------------------------------------------------------------------- */
  516.  
  517. static int _Scan_scanforfile(ScanData *scan_data) {
  518.   OSGBPBblock GBPB_buffer;
  519.   _kernel_swi_regs regs;
  520.  
  521.   scan_data->retry_position = scan_data->position[scan_data->level];
  522.   scan_data->retry_numchecked = scan_data->numchecked;
  523.   scan_data->retry_numoutput = scan_data->numoutput;
  524.  
  525.   /* construct input and output directory paths */
  526. #ifndef OLD_SCL_STUBS
  527.   char input_dir[strlen(scan_data->loadroot)+1+strlen(scan_data->relativedir)+1];
  528.   char output_dir[strlen(scan_data->saveroot)+1+strlen(scan_data->relativedir)+1];
  529. #else
  530.   char *input_dir = malloc(strlen(scan_data->loadroot)+1+strlen(scan_data->relativedir)+1);
  531.   if(input_dir == NULL)
  532.     RG_RETV("NoMem", SCAN_PHASE_ERROR)
  533.  
  534.   char *output_dir = malloc(strlen(scan_data->saveroot)+1+strlen(scan_data->relativedir)+1);
  535.   if(output_dir == NULL) {
  536.     free(input_dir);
  537.     RG_RETV("NoMem", SCAN_PHASE_ERROR)
  538.   }
  539. #endif
  540.  
  541.   if(strcmp(scan_data->relativedir, "") != 0) {
  542.     sprintf(input_dir, "%s.%s", scan_data->loadroot, scan_data->relativedir);
  543.     sprintf(output_dir, "%s.%s", scan_data->saveroot, scan_data->relativedir);
  544.   }
  545.   else {
  546.     strcpy(input_dir, scan_data->loadroot);
  547.     strcpy(output_dir, scan_data->saveroot);
  548.   }
  549.  
  550.   /* get next file */
  551.   regs.r[0] = 12; /* read entries and full info with filetype from given dir */
  552.   regs.r[1] = (int)input_dir; /* pointer to dir name */
  553.   regs.r[2] = (int)&GBPB_buffer; /* pointer to buffer */
  554.   regs.r[3] = 1; /* objects to read */
  555.   regs.r[4] = scan_data->position[scan_data->level]; /* where to start */
  556.   regs.r[5] = sizeof(OSGBPBblock); /* buffer length */
  557.   regs.r[6] = 0; /* any filename */
  558.   if(E(_kernel_swi(OS_GBPB, ®s, ®s))) {
  559. #ifdef OLD_SCL_STUBS
  560.     free(input_dir);
  561.     free(output_dir);
  562. #endif
  563.     return SCAN_PHASE_ERROR;
  564.   }
  565.   scan_data->position[scan_data->level] = regs.r[4];
  566.  
  567.   /* check for end of directory */
  568.   if(regs.r[4] == -1) {
  569.     /* =============================================== */
  570.     /* Reached end of this directory, so go up a level */
  571.  
  572.     _Scan_updatewindow(scan_data, msgs_lookup("ScanTLeave"), output_dir);
  573. #ifdef OLD_SCL_STUBS
  574.     free(input_dir);
  575.     free(output_dir);
  576. #endif
  577.  
  578.     if(scan_data->level == 0) {
  579.       /* in root dir, so finish */
  580.       RE(toolbox_delete_object(0, scan_data->window_id))
  581.       return SCAN_PHASE_IDLE;
  582.     }
  583.  
  584.     /* WE HAVE TO BE VERY CAREFUL NOT TO BUGGER UP RELATIVEDIR OR POSITION[], IN ANY CIRCUMSTANCES! */
  585.     {
  586.       char *newstring;
  587.       {
  588.         /* Find last full-stop in directory pathname (relative to root) */
  589.         int stoplen;
  590.         char *laststop = strrchr(scan_data->relativedir, '.');
  591.         if(laststop == NULL)
  592.           /* Could not find full-stop so relativedir is just leafname */
  593.           laststop = scan_data->relativedir;
  594.         stoplen = (unsigned int)laststop - (unsigned int)scan_data->relativedir;
  595.         newstring = malloc(stoplen + 1);
  596.         if(newstring == NULL)
  597.           RG_RETV("NoMem", SCAN_PHASE_ERROR)
  598.         strncpy(newstring, scan_data->relativedir, stoplen);
  599.         laststop = (char *)((unsigned int)newstring + stoplen);
  600.         *laststop = 0;
  601.       }
  602.       /* Retract array holding our position on each level */
  603.       {
  604.         int *newptr;
  605.         newptr = realloc(scan_data->position, (scan_data->level-1+1) * sizeof(int));
  606.         if(newptr == NULL) {
  607.           free(newstring);
  608.           RG_RETV("NoMem", SCAN_PHASE_ERROR)
  609.         }
  610.  
  611.         /* Now we're absolutely certain we can proceed up tree, its safe to bugger around with position and relativedir */
  612.         scan_data->level--;
  613.         free(scan_data->relativedir);
  614.         scan_data->relativedir = newstring;
  615.         scan_data->position = newptr;
  616.       }
  617.     }
  618.  
  619.     return SCAN_PHASE_SCANNING;
  620.   } /* if end of directory */
  621.  
  622.   /* ================================================================ */
  623.   /* There are further objects to scan within current directory level */
  624.   if(regs.r[3] != 1) {
  625. #ifdef OLD_SCL_STUBS
  626.     free(input_dir);
  627.     free(output_dir);
  628. #endif
  629.     R_RETV("IntErrScan", SCAN_PHASE_ERROR)
  630.   }
  631.  
  632.   free(scan_data->loadpath);
  633.   scan_data->loadpath = malloc(strlen(input_dir)+1+strlen(GBPB_buffer.filename)+1);
  634.   free(scan_data->savepath);
  635.   scan_data->savepath = malloc(strlen(output_dir)+1+strlen(GBPB_buffer.filename)+1);
  636.   if(scan_data->loadpath == NULL || scan_data->savepath == NULL) {
  637. #ifdef OLD_SCL_STUBS
  638.     free(input_dir);
  639.     free(output_dir);
  640. #endif
  641.     RG_RETV("NoMem", SCAN_PHASE_ERROR)
  642.   }
  643.  
  644.   /* make full path for file to load as */
  645.   sprintf(scan_data->loadpath, "%s.%s", input_dir, GBPB_buffer.filename);
  646. #ifdef OLD_SCL_STUBS
  647.   free(input_dir);
  648. #endif
  649.  
  650.   /* make full path for file to save as */
  651.   sprintf(scan_data->savepath, "%s.%s", output_dir, GBPB_buffer.filename);
  652. #ifdef OLD_SCL_STUBS
  653.   free(output_dir);
  654. #endif
  655.  
  656.   scan_data->input_type = GBPB_buffer.filetype;
  657.   switch(GBPB_buffer.objecttype) {
  658.  
  659.     case 1:/* object is file - check whether we shall load it */
  660.       scan_data->numchecked++;
  661.       {
  662.         char num[16];
  663. #ifndef OLD_SCL_STUBS
  664.         snprintf(num, sizeof(num), "%d", scan_data->numchecked);
  665. #else
  666.         sprintf(num, "%d", scan_data->numchecked);
  667. #endif
  668.         RE(button_set_value(0, scan_data->window_id, SCAN_SCANNED, num))
  669.       }
  670.  
  671.       if(((scan_data->input_type == FILETYPE_MAPTILES || scan_data->input_type == FILETYPE_PLANETS) && !scan_data->conv_to_sf3000)
  672.       || (scan_data->input_type == FILETYPE_SPRITE && scan_data->conv_to_sf3000)) {
  673.         scan_data->thread_state = NULL;
  674.         return SCAN_PHASE_LOAD;
  675.       }
  676.       else {
  677.         /* file of no interest */
  678.         _Scan_updatewindow(scan_data,msgs_lookup("ScanTIgnore"), scan_data->loadpath);
  679.         return SCAN_PHASE_SCANNING;
  680.       }
  681.       break;
  682.  
  683.     case 2:/* Object is directory - go down a level */
  684.     case 3:/* or image file */
  685.       _Scan_updatewindow(scan_data, msgs_lookup("ScanTOpen"), scan_data->loadpath);
  686.  
  687.       /* WE HAVE TO BE VERY CAREFUL NOT TO BUGGER UP RELATIVEDIR OR POSITION[], IN ANY CIRCUMSTANCES! */
  688.       {
  689.         char *newstring = malloc(strlen(scan_data->relativedir) + 1 + strlen(GBPB_buffer.filename) + 1);
  690.         if(newstring == NULL)
  691.           RG_RETV("NoMem", SCAN_PHASE_ERROR)
  692.         if(strcmp(scan_data->relativedir, "") != 0)
  693.           sprintf(newstring, "%s.%s", scan_data->relativedir, GBPB_buffer.filename);
  694.         else
  695.           strcpy(newstring, GBPB_buffer.filename);
  696.         {
  697.           /* Extend array holding our position on each level */
  698.           int *newptr = realloc(scan_data->position, (scan_data->level+1+1) * sizeof(int));
  699.           if(newptr == NULL) {
  700.             free(newstring);
  701.             RG_RETV("NoMem", SCAN_PHASE_ERROR)
  702.           }
  703.           /* Now we're absolutely certain we can proceed down tree, its safe to bugger around with position and relativedir */
  704.           scan_data->level++;
  705.           free(scan_data->relativedir);
  706.           scan_data->relativedir = newstring;
  707.           scan_data->position = newptr;
  708.           scan_data->position[scan_data->level] = 0; /* start at beginning of dir */
  709.         }
  710.       }
  711.       break;
  712.  
  713.   } /* what object type */
  714.   return SCAN_PHASE_SCANNING;
  715. }
  716.  
  717. /* ----------------------------------------------------------------------- */
  718.  
  719. static int _Scan_loadanimsfile(ScanData *scan_data)
  720. {
  721.   /* Load any textfile animations */
  722. #ifndef NDEBUG
  723.   _kernel_oscli("report Loading animations file");
  724. #endif
  725.  
  726. #ifndef OLD_SCL_STUBS
  727.   char anifilename[strlen(scan_data->loadpath)+4+1];
  728. #else
  729.   char *anifilename = malloc(strlen(scan_data->loadpath)+4+1);
  730.   if(anifilename == NULL)
  731.     RG_RETV("NoMem", SCAN_PHASE_ERROR) /* failure */
  732. #endif
  733.   sprintf(anifilename, "%s/ani", scan_data->loadpath);
  734.  
  735.   _Scan_updatewindow(scan_data, msgs_lookup("ScanTLoad"), anifilename);
  736.  
  737.   SF_MapTilesSetHdr *temp_anims_ptr = &scan_data->anims;
  738.   _kernel_oserror *err = load_animsfilepath(anifilename, &temp_anims_ptr, true);
  739. #ifdef OLD_SCL_STUBS
  740.   free(anifilename);
  741. #endif
  742.   if(err != NULL) {
  743.     err_report(err->errnum, msgs_lookup_sub1("LoadFail", err->errmess));
  744.     return SCAN_PHASE_ERROR; /* failure */
  745.   } else {
  746.     return SCAN_PHASE_CONVERT; /* success */
  747.   }
  748. }
  749. /* ----------------------------------------------------------------------- */
  750.  
  751. static int _Scan_loadfile(ScanData *scan_data, const volatile bool *time_up)
  752. {
  753.   _kernel_oserror *err;
  754.  
  755.   if(scan_data->thread_state == NULL) {
  756.     _Scan_updatewindow(scan_data, msgs_lookup("ScanTLoad"), scan_data->loadpath);
  757.   }
  758.  
  759.   assert(scan_data->input_type == FILETYPE_MAPTILES || scan_data->input_type == FILETYPE_PLANETS || scan_data->input_type == FILETYPE_SPRITE);
  760.  
  761.   if(scan_data->input_type == FILETYPE_SPRITE)
  762.     err = load_fileM(scan_data->loadpath, (flex_ptr)&scan_data->input_buffer, time_up, &scan_data->thread_state, true);
  763.   else
  764.     err = load_compressedM(scan_data->loadpath, (flex_ptr)&scan_data->input_buffer, time_up, &scan_data->thread_state);
  765.  
  766.   if(err != NULL) {
  767.     scan_data->input_buffer = NULL;
  768.     err_report(err->errnum, msgs_lookup_sub1("LoadFail", err->errmess));
  769.     return SCAN_PHASE_ERROR; /* fail */
  770.   }
  771.  
  772.   if(scan_data->thread_state == NULL) {
  773.     /* Have finished loading this file */
  774. #ifndef NDEBUG
  775.     _kernel_oscli("report Have finished loading");
  776. #endif
  777.  
  778.     if(scan_data->input_type == FILETYPE_SPRITE) {
  779.       /* Does the spritefile contain either valid planets or tiles? */
  780.       bool found_tile = contains_valid_tiles((spriteareaheader **)&scan_data->input_buffer);
  781.       bool found_pla = contains_valid_planets((spriteareaheader **)&scan_data->input_buffer);
  782.       if(!found_tile && !found_pla) {
  783.         /* This Sprite file is of no interest whatever */
  784.         flex_free((flex_ptr)&scan_data->input_buffer);
  785.         return SCAN_PHASE_SCANNING;
  786.       }
  787.       if(found_pla && found_tile) {
  788.         M("AutoDouble"); /* confusion overload */
  789.         return SCAN_PHASE_ERROR;
  790.       }
  791.       scan_data->conv_to_tile = found_tile;
  792.  
  793.       if(scan_data->conv_to_sf3000 && found_tile)
  794.         return SCAN_PHASE_LOADANIMS; /* new phase! */
  795.     }
  796.     return SCAN_PHASE_CONVERT; /* success */
  797.   }
  798.   else {
  799.     /* We will have to come back another time */
  800.     //unsigned int perc;
  801. #ifndef NDEBUG
  802.    _kernel_oscli("report Loading incomplete");
  803. #endif
  804.     //if(scan_data->input_type == FILETYPE_SPRITE)
  805.     //  perc = get_loadsave_perc(&scan_data->thread_state);
  806.     //else
  807.     //  perc = get_decomp_perc(&scan_data->thread_state);
  808.     return SCAN_PHASE_LOAD; /* success */
  809.   }
  810. }
  811.  
  812. /* ----------------------------------------------------------------------- */
  813.  
  814. static int _Scan_convertdata(ScanData *scan_data)
  815. {
  816.   _Scan_updatewindow(scan_data, msgs_lookup("ScanTConvert"), scan_data->loadpath);
  817.  
  818.   switch(scan_data->input_type) {
  819.     case FILETYPE_MAPTILES:
  820.       if(!tiles_to_sprites((SF_MapTilesSetHdr **)&scan_data->input_buffer, (spriteareaheader **)&scan_data->output_buffer)) {
  821.         scan_data->output_buffer = NULL;
  822.         return SCAN_PHASE_ERROR;
  823.       }
  824.  
  825.       /* Copy the tiles file header before discarding buffer */
  826.       nobudge_register(256);
  827.       memcpy(&scan_data->anims, scan_data->input_buffer, sizeof(SF_MapTilesSetHdr));
  828.       nobudge_deregister();
  829.       scan_data->output_type = FILETYPE_SPRITE;
  830.       break;
  831.  
  832.     case FILETYPE_PLANETS:
  833.       if(!planets_to_sprites((SF_PlanetsSetHdr **)&scan_data->input_buffer, (spriteareaheader **)&scan_data->output_buffer)) {
  834.         scan_data->output_buffer = NULL;
  835.         return SCAN_PHASE_ERROR;
  836.       }
  837.       scan_data->output_type = FILETYPE_SPRITE;
  838.       break;
  839.  
  840.     case FILETYPE_SPRITE:
  841.       /* Verify sprite area we will be generating output from */
  842.       if(verify_spriteareas) {
  843.         nobudge_register(256);
  844.         if(E(_swix(OS_SpriteOp, _INR(0,1), 17+256, scan_data->input_buffer))) {
  845.           nobudge_deregister();
  846.           return SCAN_PHASE_ERROR;
  847.         }
  848.         nobudge_deregister();
  849.       }
  850.  
  851.       /* Convert to MapTiles or Planets? */
  852.       if(scan_data->conv_to_tile) {
  853.         /* Convert to MapTiles set */
  854.         if(!sprites_to_tiles((spriteareaheader **)&scan_data->input_buffer, (SF_MapTilesSetHdr **)&scan_data->output_buffer, true)) {
  855.           scan_data->output_buffer = NULL;
  856.           return SCAN_PHASE_ERROR;
  857.         }
  858.         /* Check the animations (must wait til we know last tile num) */
  859.         /*if(!check_animations((SF_MapTilesSetHdr *)scan_data->output_buffer))
  860.           goto poll_err;*/
  861.         scan_data->output_type = FILETYPE_MAPTILES;
  862.       }
  863.       else {
  864.         /* Convert to Planets set */
  865.         if(!sprites_to_planets((spriteareaheader **)&scan_data->input_buffer, (SF_PlanetsSetHdr **)&scan_data->output_buffer, true)) {
  866.           scan_data->output_buffer = NULL;
  867.           return SCAN_PHASE_ERROR;
  868.         }
  869.         scan_data->output_type = FILETYPE_PLANETS;
  870.       }
  871.       break;
  872.   }
  873.   flex_free((flex_ptr)&scan_data->input_buffer);
  874.   return SCAN_PHASE_SAVE;
  875. }
  876.  
  877. /* ----------------------------------------------------------------------- */
  878.  
  879. static int _Scan_saveanimsfile(ScanData *scan_data)
  880. {
  881. #ifndef NDEBUG
  882.   _kernel_oscli("report Saving animations file");
  883. #endif
  884.  
  885. #ifndef OLD_SCL_STUBS
  886.   char ani_file_name[strlen(scan_data->savepath) + 4 + 1];
  887. #else
  888.   char *ani_file_name = malloc(strlen(scan_data->savepath) + 4 + 1);
  889.   if(ani_file_name == NULL)
  890.     RG_RETV("NoMem", SCAN_PHASE_ERROR) /* failure */
  891. #endif
  892.   sprintf(ani_file_name, "%s/ani", scan_data->savepath);
  893.  
  894.   _Scan_updatewindow(scan_data, msgs_lookup("ScanTSave"), ani_file_name);
  895.  
  896.   _kernel_oserror *err = save_animsfile(ani_file_name, &scan_data->anims);
  897. #ifdef OLD_SCL_STUBS
  898.   free(ani_file_name);
  899. #endif
  900.   if(err != NULL) {
  901.     err_report(err->errnum, msgs_lookup_sub1("SaveFail", err->errmess));
  902.     return SCAN_PHASE_ERROR; /* failure */
  903.   } else {
  904.     return SCAN_PHASE_SCANNING; /* success */
  905.   }
  906. }
  907.  
  908. /* ----------------------------------------------------------------------- */
  909.  
  910. static int _Scan_savefile(ScanData *scan_data, const volatile bool *time_up)
  911. {
  912.   if(scan_data->thread_state == NULL) {
  913.     _Scan_updatewindow(scan_data, msgs_lookup("ScanTSave"), scan_data->savepath);
  914.  
  915.     char *ourdirstart, *chopsubdir;
  916.     _kernel_osfile_block kosfb;
  917.  
  918.     /* Ensure that entirety of output file path exists */
  919.     /* saveroot = "RAM::0.$.Landscapes"
  920.        relativedir = "Planets"
  921.        savepath = "RAM::0.$.Landscapes.Planets.Earth" */
  922.     ourdirstart = (char *)(
  923.       (unsigned int)scan_data->savepath
  924.       + ((unsigned int)strrchr(scan_data->saveroot, '.')+1 - (unsigned int)scan_data->saveroot)
  925.     ); /* find saveroot leaf ("Landscapes") in savepath */
  926.     /* ourdirstart = "Landscapes.Planets.Earth" */
  927.     chopsubdir = strchr(ourdirstart, '.'); /* end of head subdirectory */
  928.     while(chopsubdir != NULL) {
  929.       *chopsubdir=0;
  930.       /* savepath = {"RAM::0.$.Landscapes", "RAM::0.$.Landscapes.Planets"} */
  931.  
  932.       /* Create subdirectory */
  933.       kosfb.start = 0; /* default number of entries */
  934.       if(_kernel_osfile(8, scan_data->savepath, &kosfb) == _kernel_ERROR) {
  935.         _kernel_oserror *e = _kernel_last_oserror();
  936.         err_report(e->errnum, msgs_lookup_sub1("DirFail", e->errmess));
  937.         return SCAN_PHASE_ERROR; /* failure */
  938.       }
  939.  
  940.       *chopsubdir='.'; /* don't vandalise savepath */
  941.       chopsubdir = strchr((char *)((unsigned int)chopsubdir + 1), '.'); /* find end of next subdirectory */
  942.     }
  943.   }
  944.  
  945.   /* time to save */
  946.   {
  947.     _kernel_oserror *err;
  948.  
  949.     assert(scan_data->output_type == FILETYPE_MAPTILES || scan_data->output_type == FILETYPE_PLANETS || scan_data->output_type == FILETYPE_SPRITE);
  950.     if(scan_data->output_type != FILETYPE_SPRITE)
  951.       err = save_compressedM(scan_data->savepath, scan_data->output_type, &scan_data->output_buffer, time_up, &scan_data->thread_state);
  952.     else
  953.       err = save_fileM(scan_data->savepath, FILETYPE_SPRITE, &scan_data->output_buffer, time_up, &scan_data->thread_state, true);
  954.  
  955.     if(err != NULL) {
  956.       err_report(err->errnum, msgs_lookup_sub1("SaveFail", err->errmess));
  957.       return SCAN_PHASE_ERROR; /* failure */
  958.     }
  959.   }
  960.   if(scan_data->thread_state == NULL) {
  961.     /* Have finished saving data */
  962. #ifndef NDEBUG
  963.     _kernel_oscli("report Have finished saving data");
  964. #endif
  965.     /* deallocate memory for output buffer */
  966.     flex_free((flex_ptr)&scan_data->output_buffer);
  967.  
  968.     /* Update count of files output */
  969.     scan_data->numoutput++;
  970.     {
  971.       char num[16];
  972. #ifndef OLD_SCL_STUBS
  973.       snprintf(num, sizeof(num), "%d", scan_data->numoutput);
  974. #else
  975.       sprintf(num, "%d", scan_data->numoutput);
  976. #endif
  977.       RE(button_set_value(0, scan_data->window_id, SCAN_CONVERTED, num))
  978.     }
  979.  
  980.     if(scan_data->input_type == FILETYPE_MAPTILES)
  981.       return SCAN_PHASE_SAVEANIMS; /* extra phase! */
  982.     else
  983.       return SCAN_PHASE_SCANNING; /* success */
  984.   }
  985.   else {
  986.     /* We will have to come back another time */
  987.     //unsigned int perc;
  988. #ifndef NDEBUG
  989.     _kernel_oscli("report Saving incomplete");
  990. #endif
  991.     //if(scan_data->output_type != FILETYPE_SPRITE)
  992.     //  perc = get_comp_perc(&scan_data->thread_state);
  993.     //else
  994.     //  perc = get_loadsave_perc(&scan_data->thread_state);
  995.     return SCAN_PHASE_SAVE; /* success */
  996.   }
  997. }
  998.  
  999.